/**
 * 
 */
package controller;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import model.EErrorPopUp;
import model.cnf.CNF;
import model.cnf.FileCNF;
import model.preprocessor.PreProcessorFactory;
import model.session.CNFUse;
import model.session.Session;
import model.solver.ImportESolver;
import model.solver.SolverFactory;
import vue.IIG;
import vue.IIGSessionManager;
import controller.xml.ParserSolverXML;
import controller.xml.ParserXML;
import controller.xml.XMLBaliseFormat;

/**
 * Implementation of {@link IController}.
 * 
 * @author GRONOWSKI Stephane svan001@aol.com
 * 
 *         igsat 2010
 * 
 */
public class Controller implements IController {

	/** Default solver directory */
	public static final String				DEFAULT_SOLVER_DIRECTORY		= System.getProperty("user.dir") + "/solveur";
	/** Default preprocessor directory */
	public static final String				DEFAULT_PREPROCESSOR_DIRECTORY	= System.getProperty("user.dir") + "/preproc";
	/** Default cnf directory */
	public static final String				DEFAULT_CNF_DIRECTORY			= System.getProperty("user.dir") + "/cnf";
	/** Default parameter directory */
	public static final String				DEFAULT_PARAMETER_DIRECTORY		= System.getProperty("user.dir") + "/param";
	/** Question asking when you close the application */
	public static final String				CLOSE_QUESTION					= "Do you really want to close the application ?\n";


	// private File solverDirectory = new File(DEFAULT_SOLVER_DIRECTORY);
	// private File preprocDirectory = new File(DEFAULT_PREPROCESSOR_DIRECTORY);
	private File							cnfDirectory					= new File(DEFAULT_CNF_DIRECTORY);

	private SolverFactory					solverFactory					= new SolverFactory(new File(DEFAULT_SOLVER_DIRECTORY));
	private PreProcessorFactory				preprocFactory					= new PreProcessorFactory(new File(
																					DEFAULT_PREPROCESSOR_DIRECTORY));

	private IIG								ig;
	private List<IExtendedSessionManager>	sessions						= new ArrayList<IExtendedSessionManager>();

	/**
	 * Create a {@link IController} for the application.
	 * 
	 * @param ig
	 *            {@link IIG} using for the application.
	 */
	public Controller(IIG ig) {
		this.ig = ig;

		loadImportedSolver();
	}

	@Override
	public boolean changeDefaultCNFDirectory(File directory) {
		if (!directory.isDirectory())
			return false;

		cnfDirectory = directory;
		return true;
	}

	@Override
	public boolean changePreProcessorDirectory(File directory) {
		if (!directory.isDirectory())
			return false;

		preprocFactory.setDirectory(directory);
		return true;
	}

	@Override
	public boolean changeSolverDirectory(File directory) {
		if (!directory.isDirectory())
			return false;

		solverFactory.setDirectory(directory);
		return true;
	}

	@Override
	public void close() {
		// Iterator<SessionManager> ite = sessions.iterator();
		if (!ig.yesNoQuestionPopup(CLOSE_QUESTION))
			return;


		Set<IExtendedSessionManager> tmp = new HashSet<IExtendedSessionManager>(sessions);


		for (IExtendedSessionManager s : tmp)
			closeSession(s);
		System.exit(0);
	}

	@Override
	public void closeSession(ISessionManager session) {
		IExtendedSessionManager ses = null;

		Iterator<IExtendedSessionManager> it = sessions.iterator();
		while (it.hasNext())
		{
			ses = it.next();
			if (ses == session)
			{
				it.remove();
				break;
			}

			ses = null;
		}
		// sessions.remove(i);
		if (!ses.close())
			ig.showErrorPopup(EErrorPopUp.ERROR_CLOSE_SESSION, ses.toString());

		ig.closeSession(session);
		System.out.println("sesison supprimer");
	}

	@Override
	public void loadSession(File session) {

		Session ses = null;
		ParserXML parser = new ParserXML(session, preprocFactory, solverFactory);
		ses = parser.run();

		// test erreur parsing
		if (ses == null)
		{// pb parsing
			ig.showErrorPopup(EErrorPopUp.ERROR_IMPORT_XML, "Error parsing xml");
			return;
		}

		// ouvre session controller
		ses.majShortestPath();
		IExtendedSessionManager man = new SessionManager(ses, solverFactory, preprocFactory);

		IIGSessionManager igman = ig.openSession(ses.getFirst(), man);
		// ouvre session ig
		if (igman == null)
		{// pb
			ig.showErrorPopup(EErrorPopUp.ERROR_OPEN_IG_SESSION, "");
			man.close();
			return;
		}

		// maj
		man.setIIGSessionManager(igman);
		sessions.add(man);
		// igman.setSessionManager(man);
	}

	@Override
	public void openSession(String cnf) {
		CNF filecnf = null;
		try
		{
			filecnf = new FileCNF(cnf);
		} catch (Exception e)
		{
			e.printStackTrace();
			ig.showErrorPopup(EErrorPopUp.ERROR_OPEN_CNF, cnf);
			return;
		}

		CNFUse cnfuse = new CNFUse(filecnf);


		// ouvre session controller
		IExtendedSessionManager man = new SessionManager(cnfuse, solverFactory, preprocFactory);

		IIGSessionManager igman = ig.openSession(cnfuse, man);
		// ouvre session ig
		if (igman == null)
		{// pb
			ig.showErrorPopup(EErrorPopUp.ERROR_OPEN_IG_SESSION, "");
			filecnf.close();
			man.close();
			return;
		}

		// maj
		man.setIIGSessionManager(igman);
		sessions.add(man);
		// igman.setSessionManager(man);
	}

	@Override
	public void openSession(File cnf) {
		openSession(cnf.getPath());
	}

	@Override
	public File getDefaultCNFDirectory() {
		return cnfDirectory;
	}

	@Override
	public File getPreProcessorDirectory() {
		return preprocFactory.getDirectory();
	}

	@Override
	public File getSolverDirectory() {
		return solverFactory.getDirectory();
	}

	@Override
	public void addAvailableSolver(ImportESolver solver) {
		solverFactory.addAvailableImport(solver);

		for (IExtendedSessionManager man : sessions)
			man.majSolver();
	}

	@Override
	public void removeAvailableSolver(ImportESolver solver) {
		solverFactory.removeAvailableImport(solver);

		for (IExtendedSessionManager man : sessions)
			man.majSolver();
	}

	@Override
	public Set<ImportESolver> getImportedSolver() {
		return solverFactory.getAvailableImport();
	}

	public void loadImportedSolver() {
		File dir = new File(DEFAULT_PARAMETER_DIRECTORY);

		if (!dir.isDirectory())
			if (dir.exists() || !dir.mkdir())
			{
				ig.showErrorPopup(EErrorPopUp.ERROR_LOAD_SOLVER, "can't create the parameter directory : " + DEFAULT_PARAMETER_DIRECTORY);
				return;
			}

		File export = new File(dir, XMLBaliseFormat.XML_EXPORT_SOLVER_FILE_NAME);
		if (!export.isFile())
			return;

		ParserSolverXML parser = new ParserSolverXML(dir);
		Set<ImportESolver> solvers = parser.run();
		if (solvers == null)
		{
			ig.showErrorPopup(EErrorPopUp.ERROR_LOAD_SOLVER, "error parsing the xml file : ");
			return;
		}
		for (ImportESolver solver : solvers)
			solverFactory.addAvailableImport(solver);

		for (IExtendedSessionManager man : sessions)
			man.majSolver();
	}

	@Override
	public void saveImportedSolver() {
		File dir = new File(DEFAULT_PARAMETER_DIRECTORY);
		File export = new File(dir, XMLBaliseFormat.XML_EXPORT_SOLVER_FILE_NAME);

		if (!dir.isDirectory())
			if (dir.exists() || !dir.mkdir())
			{
				ig.showErrorPopup(EErrorPopUp.ERROR_EXPORT_SOLVER, "can't create the parameter directory : " + DEFAULT_PARAMETER_DIRECTORY);
				return;
			}

		BufferedWriter buf = null;
		try
		{
			export.delete();
			if (!export.createNewFile())
			{// pb sort
				ig.showErrorPopup(EErrorPopUp.ERROR_EXPORT_SOLVER, "problem creating the parameter file ");
				return;
			}
			buf = new BufferedWriter(new FileWriter(export));

			// ecrit la base
			buf.write(XMLBaliseFormat.XML_PROLOG);
			buf.write("<" + XMLBaliseFormat.SET_IMPORTESOLVER + ">");

			for (ImportESolver solver : solverFactory.getAvailableImport())
				solver.exportXML(buf);

			// close
			// file.newLine();
			buf.write("</" + XMLBaliseFormat.SET_IMPORTESOLVER + ">");

		} catch (IOException e)
		{
			e.printStackTrace();
			if (buf != null)
				try
				{
					buf.close();
				} catch (IOException e1)
				{
					e1.printStackTrace();
				}

			export.delete();
			ig.showErrorPopup(EErrorPopUp.ERROR_EXPORT_SOLVER, "problem with exporting the solver in the parameter file ");

			return;
		}

		try
		{
			buf.close();
		} catch (IOException e1)
		{
			e1.printStackTrace();
			return;
		}

		return;
	}
}
